package com.glsc.ngateway.platform.service.itflow.flowstrategy;

import com.glsc.ngateway.common.api.common.enums.DictConstant;
import com.glsc.ngateway.common.api.flowable.dto.FlowDoTaskRespDto;
import com.glsc.ngateway.common.api.flowable.dto.param.ParamStopDto;
import com.glsc.ngateway.common.api.flowable.dto.task.FlowFormBaseEntityDto;
import com.glsc.ngateway.common.api.flowable.dto.task.doTaskParam.AbstractCreateParamDto;
import com.glsc.ngateway.common.api.flowable.dto.task.doTaskParam.AbstractFlowSearchParamDto;
import com.glsc.ngateway.common.api.flowable.dto.task.doTaskParam.AbstractPassParamDto;
import com.glsc.ngateway.common.api.flowable.dto.task.doTaskParam.AbstractRejectParamDto;
import com.glsc.ngateway.common.api.flowable.dto.task.formData.AbstractTaskFormDataDto;
import com.glsc.ngateway.common.api.flowable.resp.FlowableResponse;
import com.glsc.ngateway.common.api.flowable.resp.ResponseMsgDto;
import com.glsc.ngateway.common.api.platform.dto.user.PlatformUserDto;
import com.glsc.ngateway.common.base.enums.itflow.ITFlowStatus;
import com.glsc.ngateway.platform.vo.FlowTaskParamPreVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备相关流程代理类，在策略模式中相当于具体使用某一种策略的Context类？
 *
 * @author xuchang
 */
@Component
public class ItFlowStrategyProxyAdapter {
    private Map<String, AbstractItFlowStrategy> flowStrategyMap;
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    public void setAbstractItFlowStrategy(List<AbstractItFlowStrategy> flowStrategyList) {
        this.flowStrategyMap = flowStrategyList.stream().collect(Collectors.toMap(s -> s.getFlowEnum().getKey(), strategy -> strategy));
    }

    public <D extends FlowFormBaseEntityDto, T extends AbstractTaskFormDataDto<D>> FlowDoTaskRespDto createFlow(@NotNull AbstractCreateParamDto<D, T> itTaskDto, @NotNull String operatorStart, @NotNull String flowKey) {
        return Optional.ofNullable(flowStrategyMap.get(flowKey)).map(s -> {
            return s.createFlow(itTaskDto, operatorStart);
        }).get();
    }

    public <D extends FlowFormBaseEntityDto, T extends AbstractTaskFormDataDto<D>> void saveOrUpdateForm(AbstractCreateParamDto<D, T> itTaskDto, @NotBlank String operator, @NotNull String flowKey) throws Exception {
        Optional.ofNullable(flowStrategyMap.get(flowKey)).map(s -> {
            try {
                return s.saveOrUpdateForm(itTaskDto.getFlowableFormData(), operator);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }

    public <D extends FlowFormBaseEntityDto, T extends AbstractTaskFormDataDto<D>> FlowDoTaskRespDto taskAuditPass(AbstractPassParamDto<D, T> itTaskDto, String operatorAccount, @NotNull String flowKey) throws Exception {
        return Optional.ofNullable(flowStrategyMap.get(flowKey)).map(s -> {
            try {
                return s.taskAuditPass(itTaskDto, operatorAccount);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }).orElse(null);
    }

    public FlowableResponse<ResponseMsgDto> reject(AbstractRejectParamDto taskDto, String operatorStart, @NotNull String flowKey) {
        return Optional.ofNullable(flowStrategyMap.get(flowKey)).map(s -> s.reject(taskDto, operatorStart)).orElse(null);
    }

    public <D extends FlowFormBaseEntityDto, T extends AbstractTaskFormDataDto<D>> T findFormByProcessId(AbstractCreateParamDto<D, T> taskDto, String flowKey) {
        return (T) Optional.ofNullable(flowStrategyMap.get(flowKey)).map(s -> s.findFormByProcessId(taskDto.getProcessId())).orElse(null);
    }

    public List<String> pageProcessId(String flowKey, AbstractFlowSearchParamDto param, Pageable pageable) {
        return Optional.ofNullable(flowStrategyMap.get(flowKey)).map(s -> s.pageProcessId(param, pageable)).orElse(Collections.EMPTY_LIST);
    }


    /**
     * 预览发起流程审批人员
     */
    public FlowTaskParamPreVo preViewCreateFlow(String flowKey, PlatformUserDto user) {
        AbstractItFlowStrategy strategy = flowStrategyMap.get(flowKey);
        Map<String, String> userGroup = strategy.initTaskUserGroup(strategy.initDefaultTaskUserGroup(user));
        Map<String, String> conditionalVar = strategy.initTaskConditionalVar(strategy.initDefaultTaskConditionalVar(userGroup, user));
        return FlowTaskParamPreVo.build(flowKey, userGroup, conditionalVar);
    }

    /**
     * 流程终止
     */
    public <D extends FlowFormBaseEntityDto, T extends AbstractTaskFormDataDto<D>> void processStop(ParamStopDto paramStopDto, String flowKey, String operatorAccount) throws Exception {
        AbstractCreateParamDto<D, T> paramDto = new AbstractCreateParamDto<>();
        paramDto.setProcessId(paramStopDto.getProcessId());
        T flowForm = this.findFormByProcessId(paramDto, flowKey);
        if (Objects.isNull(flowForm)) {
//            throw PlatformException.error("未找到流程信息");
            logger.error("未找到流程信息");
            return;
        }
        flowForm.setIsClose(DictConstant.EVENT_FORCE_CLOSE);
        flowForm.setStatus(ITFlowStatus.UNUSUAL.getCode());
        AbstractCreateParamDto<D, T> createParam = new AbstractCreateParamDto<>();
        createParam.setFlowableFormData(flowForm);
        this.saveOrUpdateForm(createParam, operatorAccount, flowKey);
    }
}
